home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-07-28 | 28.9 KB | 1,086 lines | [TEXT/MPS ] |
- /*
- File: DiskLog.cp
-
- Copyright: © 1991-1994 by Apple Computer, Inc.
- All rights reserved.
-
- Part of the AOCE Sample SMSAM Package. Consult the license
- which came with this software for your specific legal rights.
-
- */
-
-
-
- #ifndef __DISKLOG__
- #include "DiskLog.h"
- #endif
-
- #ifndef __STDIO__
- #include "StdIO.h"
- #endif
-
- #ifndef __IOSTREAM__
- #include "IOStream.h"
- #endif
-
- #ifndef __DEBUGASSERT__
- #include "DebugAssert.h"
- #endif
-
- #ifndef __DEBUGGINGGEAR__
- #include "DebuggingGear.h"
- #endif
-
- #ifndef __ABSTRACTFILE__
- #include "AbstractFile.h"
- #endif
-
- #ifndef __CREATEOBJECT__
- #include "CreateObject.h"
- #endif
-
- #ifndef __FILESPEC__
- #include "FileSpec.h"
- #endif
-
- #ifndef __HANDLEOBJECTOWNER__
- #include "HandleObjectOwner.h"
- #endif
-
- #ifndef __BUFFER__
- #include "Buffer.h"
- #endif
-
- #ifndef __FILES__
- #include "Files.h"
- #endif
-
- #pragma segment DiskLog
-
- #undef POLYMORPHIC_DISK_LOGGING // define this to log different types of
- // TLogEntries to the same log. This option
- // requires application post-compile processing
- // using a special MPW tool.
-
- /***********************************|****************************************/
-
- Boolean
- TDiskLog::WriteEntryReconstructInfoAtCurrentMark ( const TLogEntry& entry )
- {
- #if defined ( POLYMORPHIC_DISK_LOGGING )
- return WritePolymorphicEntryReconstructInfoAtCurrentMark ( entry );
- #else
- return true; // do nothing since we don’t need object reconstruction info
- #endif
- }
-
- /***********************************|****************************************/
-
- TLogEntry*
- TDiskLog::ReconstructEntryFromInfoAtCurrentMark ()
- {
- #if defined ( POLYMORPHIC_DISK_LOGGING )
- return ReconstructPolymorphicEntryFromInfoAtCurrentMark ();
- #else
- return new TTestEntry (); // create a new object of the proper type.
- #endif
- }
-
- /***********************************|****************************************/
- /***********************************|****************************************/
-
- #if defined ( debug ) || defined ( DEBUG )
-
- #define LOG_ASSERT(EXPR) \
- { if ( !AssertDebug (EXPR,#EXPR,__FILE__,__LINE__) ) { chris << *this << endl; return 0; } }
-
- #else
-
- #define LOG_ASSERT(EXPR)\
- if ( !(EXPR) ) { return false; }
-
- #endif
-
- /***********************************|****************************************/
-
- typedef unsigned short SynchMarker;
-
- const EntryIndex TDiskLog::kInvalidIndex = (EntryIndex) 0;
- const EntryIndex kPreEntryOverhead = sizeof ( SynchMarker ) + 2 * sizeof ( EntryIndex );
- const EntryIndex kPostEntryOverhead = sizeof ( SynchMarker );
- const EntryIndex kTotalEntryOverhead = kPreEntryOverhead + kPostEntryOverhead;
- const SynchMarker kSynchStart = ( (SynchMarker) '\n' << 8 ) | (SynchMarker) '{';
- const SynchMarker kSynchStop = (SynchMarker) '}#';
- const unsigned long kMinimumEntryLength = kTotalEntryOverhead;
- const unsigned long kMaximumEntryLength = 0xFFFF;
-
- extern void Busy ( short );
- inline long Abs ( long a ) { return a < 0 ? -a : a; }
- inline Boolean IsValidEntryLength ( unsigned long supposedLength ) { return ( supposedLength >= kMinimumEntryLength ) && ( supposedLength <= kMaximumEntryLength ); }
-
- /***********************************|****************************************/
- /***********************************|****************************************/
-
- TDiskLog::TDiskLog ( const TFileSpec& spec, TPurgeCriteria* criteria ):
- fFile ( new TForkFile ( spec, TAbstractFile::kData, GetLogFileCreator (), GetLogFileType () ) ),
- fCriteria ( criteria ),
- fPermission ( kNoneOfTheAbove )
- {
- InitializeHeaderValues ( fHeader );
- }
-
- /***********************************|****************************************/
-
- TDiskLog::~TDiskLog ()
- {
- delete fFile;
- delete fCriteria;
- }
-
- /***********************************|****************************************/
-
- Boolean
- TDiskLog::Open ( LogPermission permission )
- {
- LOG_ASSERT ( kNoneOfTheAbove == fPermission );
- LOG_ASSERT ( EnsureUsabilityOnceOpen ( permission ) );
-
- long end = 0;
- LOG_ASSERT ( noErr == fFile->GetEnd ( end ) );
-
- if ( permission == kRewrite || end < sizeof ( fHeader ) )
- {
- InitializeHeaderValues ( fHeader );
- LOG_ASSERT ( noErr == fFile->SetEnd ( 0 ) );
- LOG_ASSERT ( DumpHeaderInfo () );
- }
- else
- {
- LOG_ASSERT ( LoadHeaderInfo () );
- }
-
- LOG_ASSERT ( noErr == fFile->SetPosition ( sizeof ( fHeader ) ) );
-
- fPermission = permission;
- return true;
- }
-
- /***********************************|****************************************/
-
- Boolean
- TDiskLog::Close ()
- {
- Boolean success = true;
-
- LOG_ASSERT ( kNoneOfTheAbove != fPermission );
-
- if ( fPermission != kRead )
- ASSERT ( success = DumpHeaderInfo () );
-
- fPermission = kNoneOfTheAbove;
- InitializeHeaderValues ( fHeader );
-
- return success;
- }
-
- /***********************************|****************************************/
-
- Boolean
- TDiskLog::EnsureUsabilityOnceOpen ( LogPermission /* permission */ )
- {
- // seek to the beginning
- LOG_ASSERT ( noErr == fFile->SetPosition ( 0 ) );
-
- // seek to the end
- LOG_ASSERT ( noErr == fFile->SetPosition ( fsFromLEOF, 0 ) );
-
- return true;
- }
-
- /***********************************|****************************************/
-
- Boolean
- TDiskLog::Delete ()
- {
- // LOG_ASSERT ( noErr == fFile->Delete () );
- return true;
- }
-
- /***********************************|****************************************/
-
- Boolean
- TDiskLog::AddEntry ( TLogEntry& entry )
- {
- EntryID proposed = MapToID ( fHeader.fEntryCount ) + 1, previous = entry.fID;
- entry.fID = proposed;
-
- Boolean success = WriteNewEntry ( entry );
-
- if ( success )
- {
- if ( fCriteria )
- RemoveUntil ( fCriteria->AdviseRemoveUntil ( *this ) );
- }
- else
- entry.fID = previous;
-
- return success;
- }
-
- /***********************************|****************************************/
-
- Boolean
- TDiskLog::RemoveUntil ( EntryIndex /* index */ )
- {
- NOT_IMPLEMENTED ();
- return false;
- }
-
- /***********************************|****************************************/
-
- void
- TDiskLog::AdoptPurgeCriteria ( TPurgeCriteria* criteria )
- {
- delete fCriteria;
- fCriteria = criteria;
- }
-
- /***********************************|****************************************/
-
- TPurgeCriteria*
- TDiskLog::OrphanPurgeCriteria ()
- {
- TPurgeCriteria* criteria = fCriteria;
- fCriteria = nil;
- return criteria;
- }
-
- /***********************************|****************************************/
-
- Boolean
- TDiskLog::WriteNewEntry ( TLogEntry& entry )
- {
- LOG_ASSERT ( noErr == fFile->SetPosition ( fHeader.fNewEntryOffset ) );
- LOG_ASSERT ( FlattenFromCurrentMark ( entry ) );
- fHeader.fLastEntryOffset = fHeader.fNewEntryOffset;
- LOG_ASSERT ( noErr == fFile->GetPosition ( fHeader.fNewEntryOffset ) );
- fHeader.fEntryCount++;
- LOG_ASSERT ( DumpHeaderInfo () );
- // LOG_ASSERT ( noErr == fFile->Flush () );
- return true;
- }
-
- /***********************************|****************************************/
-
- TLogEntry*
- TDiskLog::CreateEntry ( EntryIndex index )
- {
- if ( ASSERT ( IsValidIndex ( index ) ) )
- if ( ASSERT ( MoveToValidEntry ( index ) ) )
- return ResurrectFromCurrentMark ();
-
- return nil;
- }
-
- /***********************************|****************************************/
-
- Boolean
- TDiskLog::MoveToValidEntry ( EntryIndex index )
- {
- if ( !IsValidIndex ( fHeader.fCurrentEntryIndex ) )
- {
- fHeader.fCurrentEntryIndex = 1;
- fHeader.fCurrentEntryOffset = sizeof ( fHeader );
- }
-
- long fromFirstEntryJumps = (long) index - (long) 1;
- long fromLastEntryJumps = (long) index - (long) fHeader.fEntryCount;
- long fromCurrentEntryJumps = (long) index - (long) fHeader.fCurrentEntryIndex;
- long bestJump; EntryIndex bestIndex; EntryOffset bestOffset;
-
- // there are three entry positions in the file which we directly
- // know how to get to (first, current, & last).
- // this routine computes which of the three is closest to the
- // the desired index in terms of the number of jumps required.
- // once we know which of the three is closest, we start jumping
- // to the entry index which the user has requested.
-
- if ( Abs ( fromFirstEntryJumps ) <= Abs ( fromLastEntryJumps ) )
- {
- bestJump = fromFirstEntryJumps;
- bestOffset = sizeof ( fHeader );
- bestIndex = 1;
- }
- else
- {
- bestJump = fromLastEntryJumps;
- bestOffset = fHeader.fLastEntryOffset;
- bestIndex = fHeader.fEntryCount;
- }
-
- if ( Abs ( fromCurrentEntryJumps ) < Abs ( bestJump ) )
- {
- bestJump = fromCurrentEntryJumps;
- bestOffset = fHeader.fCurrentEntryOffset;
- bestIndex = fHeader.fCurrentEntryIndex;
- }
-
- LOG_ASSERT ( noErr == fFile->SetPosition ( bestOffset ) );
- fHeader.fCurrentEntryOffset = bestOffset;
- fHeader.fCurrentEntryIndex = bestIndex;
-
- while ( bestJump > 0 )
- {
- LOG_ASSERT ( MoveToNextEntry () );
- bestJump--;
- }
-
- while ( bestJump < 0 )
- {
- LOG_ASSERT ( MoveToPreviousEntry () );
- bestJump++;
- }
-
- return true;
- }
-
- /***********************************|****************************************/
-
- Boolean
- TDiskLog::MoveToNextEntry ()
- {
- Busy ( 10 );
-
- // the mark should already be at the first byte of the current entry
-
- // skip over synch marker and previous offset info
- LOG_ASSERT ( noErr == fFile->MovePosition ( sizeof ( SynchMarker ) ) );
-
- // read the entry length
- EntryOffset entryLength = 0;
- LOG_ASSERT ( noErr == fFile->ReadDataIgnore ( &entryLength, sizeof ( entryLength ) ) );
-
- // move to the next entry start
- EntryOffset offset = fHeader.fCurrentEntryOffset + entryLength;
- LOG_ASSERT ( noErr == fFile->SetPosition ( offset ) );
- fHeader.fCurrentEntryOffset = offset;
- ++fHeader.fCurrentEntryIndex;
-
- return true;
- }
-
- /***********************************|****************************************/
-
- Boolean
- TDiskLog::MoveToPreviousEntry ()
- {
- Busy ( 10 );
-
- // the mark should already be at the first byte of the current entry
-
- // skip past the entry synch marker and entry length fields
- LOG_ASSERT ( noErr == fFile->MovePosition ( sizeof ( SynchMarker ) + sizeof ( EntryOffset ) ) );
-
- // read the offset to the start of the previous entry
- EntryOffset entryOffset = 0;
- LOG_ASSERT ( noErr == fFile->ReadDataIgnore ( &entryOffset, sizeof ( entryOffset ) ) );
-
- if ( entryOffset != 0 )
- {
- // attempt to move to the start of the previous entry using a negative offset
- LOG_ASSERT ( noErr == fFile->SetPosition ( fHeader.fCurrentEntryOffset + entryOffset ) );
- fHeader.fCurrentEntryOffset += entryOffset;
- --fHeader.fCurrentEntryIndex;
- return true;
- }
- else
- {
- // we are at the first entry
- return false;
- }
- }
-
- /***********************************|****************************************/
-
- TLogEntry*
- TDiskLog::ScavengeFromMark ()
- {
- NOT_IMPLEMENTED ();
- return nil;
- }
-
- /***********************************|****************************************/
-
- FormatVersion
- TDiskLog::GetFormatVersion () const
- {
- return ( ( kMinimumEntryLength ) << ( sizeof ( FormatVersion ) / 2 * 8 ) ) | sizeof ( LogHeader );
- }
-
- /***********************************|****************************************/
-
- void
- TDiskLog::InitializeHeaderValues ( LogHeader& header ) const
- {
- header.fFormatVersion = GetFormatVersion ();
- header.fEntryCount = 0;
- header.fFirstEntryID = 1;
- header.fNewEntryOffset = header.fLastEntryOffset = sizeof ( fHeader );
- header.fCurrentEntryIndex = 1;
- header.fCurrentEntryOffset = sizeof ( fHeader );
- }
-
- /***********************************|****************************************/
-
- Boolean
- TDiskLog::HandleError ( OSErr, const char* /* file */, unsigned long /* line */ )
- {
- NOT_IMPLEMENTED ();
- return false;
- }
-
- /***********************************|****************************************/
-
- Boolean
- TDiskLog::LoadHeaderInfo ()
- {
- long endLength = 0;
- LOG_ASSERT ( noErr == fFile->GetEnd ( endLength ) );
-
- if ( !ASSERT ( endLength >= sizeof ( fHeader ) ) )
- {
- InitializeHeaderValues ( fHeader );
- return true; // we have a new virgin file
- }
-
- if ( !ASSERT ( noErr == fFile->SetPosition ( 0 ) ) )
- {
- InitializeHeaderValues ( fHeader );
- return false; // we cannot set the mark to the beginning
- }
-
- if ( !ASSERT ( noErr == fFile->ReadDataIgnore ( &fHeader, sizeof ( fHeader ) ) ) )
- {
- InitializeHeaderValues ( fHeader );
- return false; // we could not read the header info
- }
-
- if ( !ASSERT ( fHeader.fFormatVersion == GetFormatVersion () ) )
- {
- if ( !HandleUnexpectedVersion ( fHeader.fFormatVersion ) )
- {
- InitializeHeaderValues ( fHeader );
- return false; // we could not handle an unexpected version
- }
- }
-
- if ( !ASSERT ( ValidateHeaderContents ( fHeader, endLength ) ) )
- {
- InitializeHeaderValues ( fHeader );
- return false; // we have possibly corrupt header info
- }
-
- return true;
- }
-
- /***********************************|****************************************/
-
- Boolean
- TDiskLog::HandleUnexpectedVersion ( FormatVersion /* version */ )
- {
- NOT_IMPLEMENTED ();
- return false;
- }
-
- /***********************************|****************************************/
-
- OSType
- TDiskLog::GetLogFileCreator () const
- {
- return 'MPS ';
- }
-
- /***********************************|****************************************/
-
- OSType
- TDiskLog::GetLogFileType () const
- {
- return 'TEXT';
- }
-
- /***********************************|****************************************/
-
- Boolean
- TDiskLog::ValidateHeaderContents ( const LogHeader& header, unsigned long fileEnd ) const
- {
- LOG_ASSERT ( fileEnd >= ( sizeof ( LogHeader ) + kMinimumEntryLength * header.fEntryCount ) );
- LOG_ASSERT ( sizeof ( fHeader ) <= fileEnd );
- LOG_ASSERT ( header.fNewEntryOffset <= fileEnd );
- LOG_ASSERT ( header.fCurrentEntryOffset <= fileEnd );
- return true;
- }
-
- /***********************************|****************************************/
-
- Boolean
- TDiskLog::DumpHeaderInfo ()
- {
- LOG_ASSERT ( noErr == fFile->SetPosition ( 0 ) );
- LOG_ASSERT ( noErr == fFile->WriteDataIgnore ( &fHeader, sizeof ( fHeader ) ) );
- return true;
- }
-
- /***********************************|****************************************
-
- Each log entry has the following variable length file format:
-
- Description Size Offset
- ------------------------------------------ ---------- ------------
- #1. start entry synch marker M 0
- #2. total entry data length (incl. syncs) E M+E
- #3. offset to prev entry start E M
- #4. class defined construct info C M+2*E
- #5. log entry data D M+2*E+C
- #6. stop entry synch marker M M+2*E+C+D
-
- Notes:
-
- M = sizeof ( SynchMarker ).
- E = sizeof ( EntryOffset )
- C = depends on the override of WriteEntryConstruct…/ConstructEntry…
- D >= sizeof ( TLogEntry ), depends on what the entry actually writes
-
- ***********************************|****************************************/
-
- Boolean
- TDiskLog::FlattenFromCurrentMark ( TLogEntry& entry )
- {
- // get position of the start of the entry
- EntryOffset startPosition = 0;
- LOG_ASSERT ( noErr == fFile->GetPosition ( startPosition ) );
-
- // write a start synch marker
- SynchMarker marker = kSynchStart;
- LOG_ASSERT ( noErr == fFile->WriteDataIgnore ( &marker, sizeof ( marker ) ) );
-
- // write zero for length until we determine what the actual length is after writing the entry
- EntryOffset zeroValue = 0;
- LOG_ASSERT ( noErr == fFile->WriteDataIgnore ( &zeroValue, sizeof ( zeroValue ) ) );
-
- // since we know the offset of the previous entry, we can write it now
- EntryOffset previousEntryOffset = fHeader.fLastEntryOffset - startPosition;
- LOG_ASSERT ( noErr == fFile->WriteDataIgnore ( &previousEntryOffset, sizeof ( previousEntryOffset ) ) );
-
- // write the entry class information for later re-construction
- LOG_ASSERT ( WriteEntryReconstructInfoAtCurrentMark ( entry ) );
-
- // write the entry data by asking the entry to write itself
- LOG_ASSERT ( entry.WriteTo ( *fFile ) );
-
- // write a stop synch marker
- marker = kSynchStop;
- LOG_ASSERT ( noErr == fFile->WriteDataIgnore ( &marker, sizeof ( marker ) ) );
-
- // get position after writing entry data
- EntryOffset stopPosition = 0;
- LOG_ASSERT ( noErr == fFile->GetPosition ( stopPosition ) );
-
- // determine our entry’s length and check for size validity
- unsigned long entryLength = stopPosition - startPosition;
- LOG_ASSERT ( IsValidEntryLength ( entryLength ) );
-
- // move to after the start synch marker and prev offset
- LOG_ASSERT ( noErr == fFile->SetPosition ( startPosition + sizeof ( SynchMarker ) ) );
-
- // write the entry length
- LOG_ASSERT ( noErr == fFile->WriteDataIgnore ( &entryLength, sizeof ( entryLength ) ) );
-
- // return the position to the end of the entry data
- LOG_ASSERT ( noErr == fFile->SetPosition ( stopPosition ) );
-
- return true;
- }
-
- /***********************************|****************************************/
-
- TLogEntry*
- TDiskLog::ResurrectFromCurrentMark ()
- {
- TLogEntry* entry = nil;
-
- // remember the position at the start of tbe entry data
- long startPosition = 0;
- LOG_ASSERT ( noErr == fFile->GetPosition ( startPosition ) );
-
- // read a synchronization marker
- SynchMarker marker = ~kSynchStart; // cute initial value, huh?
- LOG_ASSERT ( noErr == fFile->ReadDataIgnore ( &marker, sizeof ( marker ) ) );
-
- // did we read a synch marker?
- LOG_ASSERT ( kSynchStart == marker );
-
- // read the entry length
- unsigned long expectedEntryLength = 0;
- LOG_ASSERT ( noErr == fFile->ReadDataIgnore ( &expectedEntryLength, sizeof ( expectedEntryLength ) ) );
-
- // verify expectedEntryLength
- LOG_ASSERT ( IsValidEntryLength ( expectedEntryLength ) );
-
- // skip past the prev offset info
- LOG_ASSERT ( noErr == fFile->MovePosition ( sizeof ( EntryOffset ) ) );
-
- // construct entry from info
- entry = ReconstructEntryFromInfoAtCurrentMark ();
-
- if ( entry != nil )
- {
- // read the entry data
- if ( !entry->ReadFrom ( *fFile ) )
- {
- // delete the reconstructed entry
- delete entry;
- return false;
- }
- }
- else
- {
- // advance past the entry data
- LOG_ASSERT ( noErr == fFile->SetPosition ( startPosition + expectedEntryLength - kPreEntryOverhead ) );
- }
-
- // read a synchronization marker
- marker = ~kSynchStop; // cute initial value, huh?
- LOG_ASSERT ( noErr == fFile->ReadDataIgnore ( &marker, sizeof ( marker ) ) );
-
- // did we read a synch marker?
- LOG_ASSERT ( kSynchStop == marker );
-
- // remember the position at the end of tbe entry data
- long stopPosition = 0;
- LOG_ASSERT ( noErr == fFile->GetPosition ( stopPosition ) );
-
- // ensure the expected and actual entry lengths are the same
- const unsigned long actualEntryLength = stopPosition - startPosition;
- LOG_ASSERT ( actualEntryLength == expectedEntryLength );
-
- return entry;
- }
-
- /***********************************|****************************************/
-
- const unsigned long kMinimumClassNameLength = 1;
- const unsigned long kMaximumClassNameLength = 128;
-
- inline Boolean
- IsValidClassNameLength ( unsigned long supposedLength )
- {
- return ( supposedLength >= kMinimumClassNameLength ) && ( supposedLength <= kMaximumClassNameLength );
- }
-
- /***********************************|****************************************/
-
- Boolean
- TDiskLog::WritePolymorphicEntryReconstructInfoAtCurrentMark ( const TLogEntry& entry )
- {
- // write the entry class name length and string data
- const char* entryClass = entry.GetClass ();
- unsigned short length = strlen ( entryClass );
- LOG_ASSERT ( noErr == fFile->WriteDataIgnore ( &length, sizeof ( length ) ) );
- LOG_ASSERT ( noErr == fFile->WriteDataIgnore ( entryClass, length ) );
- return true;
- }
-
- /***********************************|****************************************/
-
- TLogEntry*
- TDiskLog::ReconstructPolymorphicEntryFromInfoAtCurrentMark ()
- {
- // read the class name length
- unsigned short classNameLength = 0;
- LOG_ASSERT ( noErr == fFile->ReadDataIgnore ( &classNameLength, sizeof ( classNameLength ) ) );
-
- // is the assumed name length valid?
- LOG_ASSERT ( IsValidClassNameLength ( classNameLength ) );
-
- // read the entry class string
- char className [ kMaximumClassNameLength + 1 ];
- LOG_ASSERT ( noErr == fFile->ReadDataIgnore ( className, classNameLength ) );
- className [ classNameLength ] = 0;
-
- // create an empty object
- TLogEntry* entry = (TLogEntry*) CreateObject ( className );
-
- if ( entry == nil )
- {
- cerr << "FILE " << __FILE__ << "; LINE " << __LINE__ << "; # Could not reconstruct \"" << className << "\"\n";
- cerr.flush ();
- }
-
- return entry;
- }
-
- /***********************************|****************************************/
-
- Boolean
- TDiskLog::ValidateDiskContents ( ostream& )
- {
- NOT_IMPLEMENTED ();
- return false;
- }
-
- /***********************************|****************************************/
-
- #if debug
-
- Boolean
- TDiskLog::InvariantCheck ( ostream& out ) const
- {
- // NOT_IMPLEMENTED ();
- // *this >> out; // dump our state for now
- return true;
- }
-
- /***********************************|****************************************/
-
- Boolean
- TDiskLogEnumerator::InvariantCheck ( ostream& out ) const
- {
- NOT_IMPLEMENTED ();
- *this >> out; // dump our state for now
- return fLog.InvariantCheck ( out );
- }
-
- /***********************************|****************************************/
-
- Boolean
- TDiskLogIterator::InvariantCheck ( ostream& out ) const
- {
- return fImplementation.InvariantCheck ( out );
- }
-
- /***********************************|****************************************/
-
- ostream&
- TDiskLog::operator >> ( ostream& stream ) const
- {
- stream << "TDiskLog:" << (void*) this << "\n";
- stream << "\n\tfFile:" << fFile << endl;
- stream << "\n\tfHeader.fFormatVersion: " << (short) fHeader.fFormatVersion;
- stream << "\n\tfHeader.fEntryCount: " << fHeader.fEntryCount;
- stream << "\n\tfHeader.fFirstEntryID: " << fHeader.fFirstEntryID;
- stream << "\n\tfHeader.fLastEntryOffset: " << fHeader.fLastEntryOffset;
- stream << "\n\tfHeader.fNewEntryOffset: " << fHeader.fNewEntryOffset;
- stream << "\n\tfHeader.fCurrentEntryIndex: " << fHeader.fCurrentEntryIndex;
- stream << "\n\tfHeader.fCurrentEntryOffset: " << fHeader.fCurrentEntryOffset;
- stream << "\n\tfCriteria:" << fCriteria;
- stream << "\n\tfPermission:";
-
- switch ( fPermission )
- {
- case kRewrite:
- stream << "kRewrite\n";
- break;
-
- case kAppend:
- stream << "kAppend\n";
- break;
-
- case kRead:
- stream << "kRead\n";
- break;
-
- case kNoneOfTheAbove:
- stream << "kNoneOfTheAbove\n";
- break;
- }
-
- return stream;
- }
-
- #endif // debug
-
- /***********************************|****************************************/
- /***********************************|****************************************/
-
- TDiskLogEnumerator::TDiskLogEnumerator ( TDiskLog& log ):
- fLog ( log ),
- fEntryCache ( fLog.CreateEntry ( 1 ) ),
- fFirstEntryID ( fEntryCache && fLog.IsValidIndex ( 1 )
- ? fEntryCache->GetID () : TLogEntry::kInvalidID )
- {
- }
-
- /***********************************|****************************************/
-
- TDiskLogEnumerator::~TDiskLogEnumerator ()
- {
- delete fEntryCache;
- }
-
- /***********************************|****************************************/
-
- const TLogEntry*
- TDiskLogEnumerator::GetEntryByIndex ( EntryIndex index )
- {
- delete fEntryCache;
- fEntryCache = fLog.CreateEntry ( index );
- return fEntryCache;
- }
-
- /***********************************|****************************************/
-
- ostream&
- TDiskLogEnumerator::operator >> ( ostream& stream ) const
- {
- stream << "TDiskLogEnumerator:" << (void*) this << "\n";
- stream << "\tfEntryCache:" << fEntryCache << "\n";
- stream << "\tfFirstEntryID:" << fFirstEntryID << "\n";
- fLog >> stream;
- return stream;
- }
-
- /***********************************|****************************************/
- /***********************************|****************************************/
-
- TDiskLogIterator::TDiskLogIterator ( TDiskLog& log ):
- fLog ( log ),
- fImplementation ( fLog ),
- fNextIndex ( TDiskLog::kInvalidIndex )
- {
- }
-
- /***********************************|****************************************/
-
- TDiskLogIterator::~TDiskLogIterator ()
- {
- }
-
- /***********************************|****************************************/
-
- const TLogEntry*
- TDiskLogIterator::GetFirstEntry ()
- {
- fNextIndex = 1;
- return GetNextEntry ();
- }
-
- /***********************************|****************************************/
-
- const TLogEntry*
- TDiskLogIterator::GetNextEntry ()
- {
- if ( fLog.IsValidIndex ( fNextIndex ) )
- {
- const TLogEntry* entry = fImplementation.GetEntryByIndex ( fNextIndex );
-
- if ( entry )
- ++fNextIndex;
- else
- fNextIndex = TDiskLog::kInvalidIndex;
-
- return entry;
- }
- else
- {
- return nil;
- }
- }
-
- /***********************************|****************************************/
-
- const TLogEntry*
- TDiskLogIterator::GetLastEntry ()
- {
- fNextIndex = fImplementation.CountEntries ();
- return GetPreviousEntry ();
- }
-
- /***********************************|****************************************/
-
- const TLogEntry*
- TDiskLogIterator::GetPreviousEntry ()
- {
- if ( fLog.IsValidIndex ( fNextIndex ) )
- {
- const TLogEntry* entry = fImplementation.GetEntryByIndex ( fNextIndex );
-
- if ( entry )
- --fNextIndex;
- else
- fNextIndex = TDiskLog::kInvalidIndex;
-
- return entry;
- }
- else
- {
- return nil;
- }
- }
-
- /***********************************|****************************************/
-
- TLogEntry*
- TDiskLogIterator::AdoptFirstEntry ()
- {
- fNextIndex = 1;
- return AdoptNextEntry ();
- }
-
- /***********************************|****************************************/
-
- TLogEntry*
- TDiskLogIterator::AdoptNextEntry ()
- {
- if ( fLog.IsValidIndex ( fNextIndex ) )
- {
- TLogEntry* entry = fImplementation.AdoptEntryByIndex ( fNextIndex );
-
- if ( entry )
- ++fNextIndex;
- else
- fNextIndex = TDiskLog::kInvalidIndex;
-
- return entry;
- }
- else
- {
- return nil;
- }
- }
-
- /***********************************|****************************************/
-
- TLogEntry*
- TDiskLogIterator::AdoptLastEntry ()
- {
- fNextIndex = fImplementation.CountEntries ();
- return AdoptPreviousEntry ();
- }
-
- /***********************************|****************************************/
-
- TLogEntry*
- TDiskLogIterator::AdoptPreviousEntry ()
- {
- if ( fLog.IsValidIndex ( fNextIndex ) )
- {
- TLogEntry* entry = fImplementation.AdoptEntryByIndex ( fNextIndex );
-
- if ( entry )
- --fNextIndex;
- else
- fNextIndex = TDiskLog::kInvalidIndex;
-
- return entry;
- }
- else
- {
- return nil;
- }
- }
-
- /***********************************|****************************************/
-
- ostream&
- TDiskLogIterator::operator >> ( ostream& stream ) const
- {
- stream << "TDiskLogIterator:" << (void*) this << "\n";
- stream << "fNextIndex:" << fNextIndex << "\n";
- fImplementation >> stream;
- stream.flush ();
- return stream;
- }
-
- /***********************************|****************************************/
- /***********************************|****************************************/
-
- EntryIndex
- TFileSizePurgeCriteria::AdviseRemoveUntil ( const TDiskLog& log )
- {
- return TDiskLog::kInvalidIndex;
- }
-
- /***********************************|****************************************/
-
- EntryIndex
- TEntryCountCriteria::AdviseRemoveUntil ( const TDiskLog& log )
- {
- return TDiskLog::kInvalidIndex;
- }
-
- /***********************************|****************************************/
- /***********************************|****************************************/
-
- extern ostream& DumpHex (ostream& s, const void *p, unsigned long size);
-
- void TDiskLog::DumpLog ( ostream& stream, const FSSpec& spec )
- {
- short refNum = -1;
- ASSERT_RETURN ( noErr == ::FSpOpenDF ( &spec, fsRdPerm, &refNum ) );
- TAbstractFile* file = new TWrapperFile ( refNum, true );
- THandleObjectOwner owner ( file );
-
- LogHeader header;
- ASSERT_RETURN ( noErr == file->SetPosition ( 0 ) );
- ASSERT_RETURN ( noErr == file->ReadDataIgnore ( &header, sizeof ( header ) ) );
-
- stream << "fFormatVersion: " << (short) header.fFormatVersion << endl;
- stream << "fEntryCount: " << header.fEntryCount << endl;
- stream << "fFirstEntryID: " << header.fFirstEntryID << endl;
- stream << "fLastEntryOffset: " << header.fLastEntryOffset << endl;
- stream << "fNewEntryOffset: " << header.fNewEntryOffset << endl;
- stream << "fCurrentEntryIndex: " << header.fCurrentEntryIndex << endl;
- stream << "fCurrentEntryOffset: " << header.fCurrentEntryOffset << endl;
-
- long position, count = header.fEntryCount;
- ASSERT_RETURN ( noErr == file->SetPosition ( sizeof ( header ) ) );
-
- while ( --count >= 0 )
- {
- stream << "\nEntry #" << header.fEntryCount - count << " @ file position " << file->GetPosition () << endl;
-
- // try to read a start entry synch marker
- SynchMarker marker = ~kSynchStart;
- ASSERT_RETURN ( noErr == file->ReadDataIgnore ( &marker, sizeof ( marker ) ) );
- ASSERT_RETURN ( kSynchStart == marker );
- stream << "start synch marker: okay" << endl;
-
- // read current entry length
- long length = 0;
- ASSERT_RETURN ( noErr == file->Read ( length ) );
- stream << "total entry length: " << length << endl;
- length -= kTotalEntryOverhead;
- stream << "entry data length: " << length << endl;
-
- // read the offset to the previous entry
- ASSERT_RETURN ( noErr == file->Read ( position ) );
- stream << "previous entry offset: " << position << endl;
-
- // read the entry data
- CBuffer buffer ( length );
- ASSERT_RETURN ( noErr == file->ReadDataIgnore ( (void*) buffer.GetPhysicalStart (), buffer.GetPhysicalLength () ) );
- DumpHex ( stream, buffer.GetPhysicalStart (), buffer.GetPhysicalLength () );
-
- // try to read a stop entry synch marker
- marker = ~kSynchStop;
- ASSERT_RETURN ( noErr == file->ReadDataIgnore ( &marker, sizeof ( marker ) ) );
- ASSERT_RETURN ( kSynchStop == marker );
- stream << "stop synch marker: okay" << endl;
- }
- }
-
- /***********************************|****************************************/
-
- void TDiskLog::DumpLog ( ostream& stream )
- {
- StandardFileReply reply;
- OSType type[4] = { 'TEXT', ' ', ' ', ' '};
-
- ::StandardGetFile ( nil, 1, type, &reply );
-
- if ( reply.sfGood )
- DumpLog ( stream, reply.sfFile );
- }
-
- /***********************************|****************************************/
-